// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "sw/device/lib/base/math.h"

#include <ostream>
#include <stdint.h>
#include <tuple>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

namespace math_unittest {
namespace {

struct DivVector {
  uint64_t a, b, q, r;

  friend void operator<<(std::ostream &out, const DivVector &v) {
    out << "{" << v.a << ", " << v.b << ", " << v.q << ", " << v.r << "}";
  }
};

class UDivTest : public testing::TestWithParam<DivVector> {};

TEST_P(UDivTest, UDiv64) {
  uint64_t rem;
  EXPECT_EQ(udiv64_slow(GetParam().a, GetParam().b, &rem), GetParam().q);
  EXPECT_EQ(rem, GetParam().r);
}

// Simple python snippet for generating vectors:
//
// import random
// # Full division.
// for _ in range(0, 32):
//   a, b = random.getrandbits(64), random.getrandbits(64)
//   print(f"{{{a}ull, {b}ull, {a//b}ull, {a%b}ull}},")
//
// # Div by u48
// for _ in range(0, 32):
//   a, b = random.getrandbits(64), random.getrandbits(48)
//   print(f"{{{a}ull, {b}ull, {a//b}ull, {a%b}ull}},")
//
// # Div by u32
// for _ in range(0, 32):
//   a, b = random.getrandbits(64), random.getrandbits(32)
//   print(f"{{{a}ull, {b}ull, {a//b}ull, {a%b}ull}},")
//
// # Product of u32s.
// for _ in range(0, 32):
//   b, q = random.getrandbits(32), random.getrandbits(32)
//   print(f"{{{b*q}ull, {b}ull, {q}ull, 0}},")
//
// clang-format off
constexpr DivVector kDivVectors[] = {
  {16547064864992412266ull, 15362666177494521751ull, 1ull, 1184398687497890515ull},
  {15117832593278048550ull, 9509133006104311255ull, 1ull, 5608699587173737295ull},
  {7700533544865790561ull, 16200507889521424080ull, 0ull, 7700533544865790561ull},
  {15751090594484430019ull, 4841336985583654393ull, 3ull, 1227079637733466840ull},
  {1569256689953856309ull, 15136191600906927243ull, 0ull, 1569256689953856309ull},
  {11646355910642376023ull, 16233286557913565679ull, 0ull, 11646355910642376023ull},
  {11467848857967805770ull, 15343115856225830326ull, 0ull, 11467848857967805770ull},
  {7082930862597735748ull, 13044336721903538272ull, 0ull, 7082930862597735748ull},
  {7440142190527596899ull, 10232543569022431683ull, 0ull, 7440142190527596899ull},
  {6162319322407126380ull, 14510700894994718373ull, 0ull, 6162319322407126380ull},
  {11421574008009519807ull, 3446073093067775855ull, 3ull, 1083354728806192242ull},
  {13590081538404264686ull, 5283212502034404741ull, 2ull, 3023656534335455204ull},
  {14232045355477928062ull, 539825197847590283ull, 26ull, 196590211440580704ull},
  {12580731027378952841ull, 16693509274214597629ull, 0ull, 12580731027378952841ull},
  {17671460965360506731ull, 11247238544147177319ull, 1ull, 6424222421213329412ull},
  {9664461898672776233ull, 9295631859719160580ull, 1ull, 368830038953615653ull},
  {11015643691959628501ull, 11371567295203483667ull, 0ull, 11015643691959628501ull},
  {8617136599055270914ull, 14553847862380133083ull, 0ull, 8617136599055270914ull},
  {17480416258340506086ull, 5930856364822663088ull, 2ull, 5618703528695179910ull},
  {14301781298682298274ull, 13686260976492283484ull, 1ull, 615520322190014790ull},
  {12717390489997499836ull, 12396402423110714892ull, 1ull, 320988066886784944ull},
  {9478693902079965650ull, 13922637938150164298ull, 0ull, 9478693902079965650ull},
  {2218148139848502258ull, 16575500956377955560ull, 0ull, 2218148139848502258ull},
  {6715234203200040462ull, 7716128746410333163ull, 0ull, 6715234203200040462ull},
  {10620210067079001965ull, 2822959022621217088ull, 3ull, 2151332999215350701ull},
  {14376175987504050882ull, 9698201778735636497ull, 1ull, 4677974208768414385ull},
  {17907411000270102820ull, 4932086816672498435ull, 3ull, 3111150550252607515ull},
  {2009523729344663635ull, 9177774962461691174ull, 0ull, 2009523729344663635ull},
  {7794275604495320889ull, 17051579788896461924ull, 0ull, 7794275604495320889ull},
  {1908688452509192803ull, 9477953155444810610ull, 0ull, 1908688452509192803ull},
  {9865370653618144874ull, 2917100723726114133ull, 3ull, 1114068482439802475ull},
  {14868378943466010358ull, 6893180186547617045ull, 2ull, 1082018570370776268ull},

  {15589205337902788058ull, 113947965797624ull, 136809ull, 98085095646242ull},
  {154443034356190258ull, 212455867024500ull, 726ull, 200074896403258ull},
  {14373381053726099454ull, 73780700389417ull, 194812ull, 15249462994850ull},
  {12817128855238948341ull, 281345225603344ull, 45556ull, 165757653009077ull},
  {6160912619711259892ull, 28980646173628ull, 212587ull, 3991598204256ull},
  {15269508067345212820ull, 45485386217644ull, 335701ull, 18428695904376ull},
  {7988213334521806465ull, 80165028719043ull, 99647ull, 8717755328644ull},
  {17258038462583660946ull, 251077212750735ull, 68735ull, 246244161890721ull},
  {1207754801805538860ull, 263416992465745ull, 4584ull, 251308342563780ull},
  {8563707882399609092ull, 165228409036947ull, 51829ull, 84670423683029ull},
  {746182492253572191ull, 195673554129159ull, 3813ull, 79230359088924ull},
  {8496739951993591715ull, 228035340749822ull, 37260ull, 143155655223995ull},
  {17292881127045336612ull, 248845483734607ull, 69492ull, 110771360026968ull},
  {12005998103417887352ull, 252693626264731ull, 47512ull, 18532327988080ull},
  {13076033720356300636ull, 69662783623236ull, 187704ull, 50583140410492ull},
  {13331639988452463714ull, 232041084383213ull, 57453ull, 183567383727225ull},
  {11740525896774895061ull, 142808904399401ull, 82211ull, 63057195739450ull},
  {17175044619609759631ull, 158020044602567ull, 108689ull, 3991801354968ull},
  {11951085009197228545ull, 189341158583116ull, 63119ull, 60420589529741ull},
  {17835462114951798285ull, 162607057461277ull, 109684ull, 69624369091817ull},
  {6950646436399140076ull, 14758119174077ull, 470971ull, 290864921309ull},
  {6726003104404773273ull, 270548366585651ull, 24860ull, 170711085489413ull},
  {6399411722239535722ull, 266575135796259ull, 24006ull, 9012314542168ull},
  {13670372028797309326ull, 245433997117396ull, 55698ull, 189257352586918ull},
  {4411737990115626057ull, 46185890582147ull, 95521ull, 15535818362470ull},
  {6658768816131697888ull, 128030080935156ull, 52009ull, 52336775169484ull},
  {7484953986642594286ull, 222513489770074ull, 33638ull, 45217756845074ull},
  {11165857475563613320ull, 122823649010094ull, 90909ull, 82367704977874ull},
  {5769661111434898342ull, 166479613883085ull, 34656ull, 143612702704582ull},
  {595988210750343410ull, 96632566780240ull, 6167ull, 55171416603330ull},
  {10823039041320808771ull, 194044969522035ull, 55775ull, 180866229306646ull},
  {8191868136837774263ull, 21974809109129ull, 372784ull, 10897900229127ull},

  {10181553883373884575ull, 3338185436ull, 3050026452ull, 1892731503ull},
  {1780389784881562605ull, 3324035064ull, 535611012ull, 329037837ull},
  {11209516958321762174ull, 3248971057ull, 3450174458ull, 2679100068ull},
  {553300379499061655ull, 1886172062ull, 293345655ull, 528971045ull},
  {9905174405193618327ull, 219401111ull, 45146418630ull, 100520397ull},
  {8240184070322019093ull, 2529206559ull, 3258011506ull, 49351239ull},
  {558416785225208748ull, 588318741ull, 949173885ull, 211929963ull},
  {18070010578094920982ull, 1478064986ull, 12225450673ull, 263485404ull},
  {1762942926120765520ull, 2874579770ull, 613287181ull, 2417837150ull},
  {18222958206762584970ull, 3886108634ull, 4689255994ull, 1442932774ull},
  {6372532333203232188ull, 872018175ull, 7307797607ull, 677724963ull},
  {11812660707898862825ull, 3632374734ull, 3252049023ull, 3024277943ull},
  {1907291528073709144ull, 2685986883ull, 710089665ull, 2129844949ull},
  {11884325264570431564ull, 2825710504ull, 4205783022ull, 1760168476ull},
  {9500265779433438259ull, 515505699ull, 18429021828ull, 104040487ull},
  {2640496290484060703ull, 2661299951ull, 992182895ull, 637522558ull},
  {8314245057884472092ull, 1480724187ull, 5614985647ull, 713728103ull},
  {8096890401121445834ull, 2938029060ull, 2755891870ull, 843703634ull},
  {4445853448633802600ull, 1799659643ull, 2470385700ull, 1699497500ull},
  {3731376883336662139ull, 1150569083ull, 3243070701ull, 782924956ull},
  {1426363467586554810ull, 2933758551ull, 486189794ull, 2030126316ull},
  {7946227974190787701ull, 4065181770ull, 1954704223ull, 1109172991ull},
  {9269622039625861421ull, 3429366141ull, 2703013227ull, 276914414ull},
  {13105234812485708591ull, 2360662048ull, 5551508240ull, 1158433071ull},
  {13264580795231265125ull, 3140285014ull, 4224005380ull, 1361889805ull},
  {13368532004903007054ull, 1424435189ull, 9385145851ull, 841256215ull},
  {4711664378505588438ull, 2544984418ull, 1851352937ull, 1622052772ull},
  {8484620585051396670ull, 10958842ull, 774226016311ull, 9724808ull},
  {2093701182484354126ull, 1297611383ull, 1613504019ull, 913705849ull},
  {98846011012594231ull, 774248727ull, 127666998ull, 331182685ull},
  {8505512273053765473ull, 2554347139ull, 3329818466ull, 1037296699ull},
  {17900303074650649604ull, 1271259881ull, 14080758263ull, 839502901ull},

  {2618787189332778102ull, 1221109647ull, 2144596266ull, 0},
  {4661566478789449783ull, 3617798021ull, 1288509323ull, 0},
  {1193973743395921536ull, 321518936ull, 3713540976ull, 0},
  {1737911512256958624ull, 687157507ull, 2529131232ull, 0},
  {181249124289945250ull, 1378418975ull, 131490590ull, 0},
  {2146345082550878040ull, 733156664ull, 2927539485ull, 0},
  {1622949150476392830ull, 1585888830ull, 1023368801ull, 0},
  {663876118781380205ull, 296679587ull, 2237687215ull, 0},
  {2777990016098405460ull, 815307460ull, 3407291301ull, 0},
  {957942499325074748ull, 4028803567ull, 237773444ull, 0},
  {4892243197152869016ull, 2252872938ull, 2171557532ull, 0},
  {5054963385063225690ull, 1548826251ull, 3263738190ull, 0},
  {6789579935278623548ull, 3898192909ull, 1741724972ull, 0},
  {8115405604890247545ull, 3301069065ull, 2458417393ull, 0},
  {4178534208521384192ull, 4099695136ull, 1019230472ull, 0},
  {674548788821792312ull, 1522493188ull, 443055374ull, 0},
  {16551611124853978205ull, 4017419995ull, 4119960359ull, 0},
  {461883617422797520ull, 2727619280ull, 169335809ull, 0},
  {8782840679992124220ull, 3015837441ull, 2912239420ull, 0},
  {4298054348781624779ull, 1661399521ull, 2587008299ull, 0},
  {2889455385802288061ull, 2231595817ull, 1294793333ull, 0},
  {13313999585402914820ull, 3383189890ull, 3935339138ull, 0},
  {13696572262444784196ull, 3568739493ull, 3837929972ull, 0},
  {2301671643187023760ull, 3054807688ull, 753458770ull, 0},
  {461135315050680928ull, 202385288ull, 2278502156ull, 0},
  {300468280288186332ull, 147052332ull, 2043274501ull, 0},
  {2266869802878007376ull, 592980332ull, 3822841468ull, 0},
  {1279072648848501356ull, 1252368991ull, 1021322516ull, 0},
  {6839727804122956563ull, 3297147757ull, 2074437759ull, 0},
  {4572339959429543082ull, 3727623342ull, 1226609971ull, 0},
  {12435319632655456416ull, 3368334101ull, 3691830816ull, 0},
  {16449272219650625118ull, 3921581046ull, 4194551133ull, 0},
};
// clang-format on

INSTANTIATE_TEST_SUITE_P(UDiv, UDivTest, testing::ValuesIn(kDivVectors));

}  // namespace
}  // namespace math_unittest
